#include "SqlRecord.h"


namespace sql
{

Record::Record(const FieldSet* fields)
    : _fields(fields)
{
    initColumnCount(_fields->count());
}

Record::Record(Record* record)
    : _fields(record->_fields)
{
    initColumnCount(_fields->count());
    _values = record->_values;
}

Record::Record(const Record& record)
    : _fields(record._fields)
{
    initColumnCount(_fields->count());
    _values = record._values;
}

const FieldSet* Record::fields() const
{
    return _fields;
}

void Record::initColumnCount(int columns)
{
    _values.resize(columns);
}

void Record::initColumnValue(int column_index, char* value, field_type type)
{
    _values[column_index].setValue(value, type);
}

void Record::toSqlInsert(string *outFieldNames, string *outValues)
{
    string *f = outFieldNames;
    string *v = outValues;

    if ((!f) &&
            (!v))
    {
        return;
    }

    for (int index = 0; index < _fields->count(); index++)
    {
        if (const Field* field = _fields->getByIndex(index))
        {
            if (field->isIgnored())
            {
                continue;
            }

            string insertValue;

            if (Value* value = getValue(field->getName()))
            {
                if (value->isIgnored())
                {
                    continue;
                }

                if (v)
                {
                    insertValue = value->toSql(field->getType());
                }
            }
            else
            {
                if (v)
                {
                    insertValue = "NULL";
                }
            }

            if (f)
            {
                if (!(*f).empty())
                {
                    (*f) += ", ";
                }

                (*f) += field->getName();
            }

            if (v)
            {
                if (!(*v).empty())
                {
                    (*v) += ", ";
                }

                (*v) += insertValue;
            }

        }
    }
}

int Record::columnCount()
{
    return _values.size();
}

const Value* Record::getValue(int column_index) const
{
    if ((column_index >= 0) && (column_index < (int)_values.size()))
    {
        return &_values.at(column_index);
    }

    return NULL;
}

const Value* Record::getValue(string fieldName) const
{
    if (const Field* field = _fields->getByName(fieldName))
    {
        return getValue(field->getIndex());
    }

    return NULL;
}

Value* Record::getValue(int column_index)
{
    if ((column_index >= 0) && (column_index < (int)_values.size()))
    {
        return &_values.at(column_index);
    }

    return NULL;
}

Value* Record::getValue(string fieldName)
{
    if (const Field* field = _fields->getByName(fieldName))
    {
        return getValue(field->getIndex());
    }

    return NULL;
}

Value* Record::getKeyIdValue()
{
    for (int index = 0; index < _fields->count(); index++)
    {
        if (const Field* field = _fields->getByIndex(index))
        {
            if (field->isKeyIdField())
            {
                return getValue(field->getIndex());
            }
        }
    }

    return NULL;
}

string Record::toString()
{
    string s;

    for (int column = 0; column < columnCount(); column++)
    {
        if (const Field* field = _fields->getByIndex(column))
        {
            if (field->isIgnored())
            {
                continue;
            }
        }

        if (Value* value = getValue(column))
        {
            if (value->isIgnored())
            {
                continue;
            }

            if (!s.empty())
            {
                s += "|";
            }

            s += value->toString();
        }
    }

    return s;
}

string Record::toSql()
{
    string values;

    toSqlInsert(NULL, &values);

    return values;
}

void Record::setIgnored(int index)
{
    if (Value* v = getValue(index))
    {
        v->setIgnored();
    }
}

void Record::setNull(int index)
{
    if (Value* v = getValue(index))
    {
        v->setNull();
    }
}

void Record::setString(int index, string value)
{
    if (Value* v = getValue(index))
    {
        v->setString(value);
    }
}

void Record::setInteger(int index, integer value)
{
    if (Value* v = getValue(index))
    {
        v->setInteger(value);
    }
}

void Record::setDouble(int index, double value)
{
    if (Value* v = getValue(index))
    {
        v->setDouble(value);
    }
}

void Record::setBool(int index, bool value)
{
    if (Value* v = getValue(index))
    {
        v->setBool(value);
    }
}

void Record::setTime(int index, time value)
{
    if (Value* v = getValue(index))
    {
        v->setTime(value);
    }
}

const Field* Record::fieldByName(string fieldName) const
{
    if (const Field* field = _fields->getByName(fieldName))
    {
        return field;
    }

    THROW_EXCEPTION("Record::fieldByName: field '" + fieldName + "' not found")
    return NULL;
}

void Record::setIgnored(string fieldName)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setIgnored(field->getIndex());
    }
}

void Record::setNull(string fieldName)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setNull(field->getIndex());
    }
}

void Record::setString(string fieldName, string value)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setString(field->getIndex(), value);
    }
}

void Record::setInteger(string fieldName, integer value)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setInteger(field->getIndex(), value);
    }
}

void Record::setDouble(string fieldName, double value)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setDouble(field->getIndex(), value);
    }
}

void Record::setBool(string fieldName, bool value)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setBool(field->getIndex(), value);
    }
}

void Record::setTime(string fieldName, time value)
{
    if (const Field* field = fieldByName(fieldName))
    {
        setTime(field->getIndex(), value);
    }
}

string Record::toSqlInsert(string tableName)
{
    string f;
    string v;
    toSqlInsert(&f, &v);

    string s = "insert into " + tableName + " ";

    s += "(" + f + ")";

    s += " values ";

    s += "(" + v + ")";

    return s;
}

string Record::toSqlUpdate(string tableName)
{
    string s;
    string whereClause;

    for (int index = 0; index < _fields->count(); index++)
    {
        if (const Field* field = _fields->getByIndex(index))
        {
            if (field->isIgnored())
            {
                continue;
            }

            if (Value* value = getValue(field->getName()))
            {
                if (value->isIgnored())
                {
                    continue;
                }

                if (field->isPrimaryKey())
                {
                    if (whereClause.length() > 0)
                    {
                        whereClause += " AND ";
                    }

                    whereClause += field->getName() + "=" + value->toSql(field->getType());
                }
                else
                {
                    if (!s.empty())
                    {
                        s += ", ";
                    }

                    s += field->getName() + "=" + value->toSql(field->getType());
                }
            }
        }
    }

    if (whereClause.length() > 0)
    {
        s += " where " + whereClause;
    }

    return "update " + tableName + " set " + s;
}

string Record::toSqlReplace(string tableName)
{
    string s = "replace into " + tableName + " ";

    s += "(" + _fields->toString() + ")";

    s += " values ";

    s += "(" + toSql() + ")";

    return s;
}

bool Record::equalsColumnValue(Record* record, string fieldName)
{
    if (record)
    {
        if (Value* value1 = getValue(fieldName))
            if (Value* value2 = record->getValue(fieldName))
            {
                return value1->equals(*value2);
            }
    }

    return false;
}

bool Record::equalsValues(Record* record)
{
    if (record)
    {
        for (int index = 0; index < _fields->count(); index++)
        {
            if (const Field* field = _fields->getByIndex(index))
            {
                if (field->isKeyIdField())
                {
                    continue;
                }

                if (Value* value1 = getValue(field->getName()))
                    if (Value* value2 = record->getValue(field->getName()))
                        if (!value1->equals(*value2))
                        {
                            return false;
                        }
            }
        }

        return true;
    }

    return false;
}


//sql eof
};
